#pragma once
#include <iostream>
#include <memory>

#include "InetAddr.hpp"
#include "Socket.hpp"
#include "Connection.hpp"
#include "Epoller.hpp"
#include "IOService.hpp"

using namespace socket_ns;

class Listener
{
public:
    Listener(uint32_t port, IOService &hc) : _port(port),
                                             _listensock(std::make_unique<TcpSocket>()),
                                             _hc(hc)
    {
        InetAddr addr("0", _port);
        _listensock->BuildListenSocket(addr);
    }

    void Accepter(Connection *conn)
    {
        // LOG(DEBUG, "get a new link,conn fd: %d\n", conn->Sockfd());
        while (true)
        {
            InetAddr clientaddr;
            int code = 0;
            int sockfd = _listensock->Accepter(&clientaddr, &code);
            if (sockfd >= 0)
            {
                LOG(DEBUG, "get a new link,conn fd: %d\n", sockfd);
                conn->_R->AddConnection(sockfd, EPOLLIN | EPOLLET,
                                        std::bind(&IOService::HandlerRecv, &_hc, std::placeholders::_1),
                                        std::bind(&IOService::HandlerSend, &_hc, std::placeholders::_1),
                                        std::bind(&IOService::HandlerExcept, &_hc, std::placeholders::_1));
            }

            else
            {
                if (code == EWOULDBLOCK || code == EAGAIN)
                {
                    LOG(DEBUG, "accepter all link!\n");
                    break;
                }
                else if (code == EINTR)
                {
                    LOG(DEBUG, "accepter interupt by signal!\n");
                    continue;
                }
                else
                {
                    LOG(WARNING, "accept error!\n");
                    break;
                }
            }
        }
    }

    int Sockfd()
    {
        return _listensock->SockFd();
    }

    ~Listener()
    {
        _listensock->Close();
    }

private:
    uint32_t _port;
    std::unique_ptr<Socket> _listensock;
    IOService &_hc;
};